﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using MoonLight.LibCommon;
using MoonLight.LibSocket;
using System.Threading;

namespace MapleLeaf
{
    class TcpClient : Notifier
    {
        public TcpClient(string ip)
        {
            m_ip = ip;
            m_port = 9527;
            m_state = CmdState.STATE_UNKNOWN;
            m_sock = new AsynTcpSocket(this);
            m_fomartor = new RequestFomator();
        }

        public void Run()
        {
            connect_svr();
            while (true) {
                m_mre.Reset();
                m_mre.WaitOne();
                string request = read_request();
                Console.WriteLine("send request [" + request + "]");
                byte[] req_bytes = Encoding.UTF8.GetBytes(request);
                m_sock.Send(req_bytes);
            }
        }

        private void connect_svr()
        {
            if (m_sock.CreateSocket() < 0) {
                Console.WriteLine("create sock fail");
                return;
            }
            if (m_sock.Connect(m_ip, m_port) < 0) {
                Console.WriteLine("connect to svr fail");
                return;
            }
        }

        public override void handle_message(MessageInfo msg)
        {
            switch ((CommonDefine.MsgType_e)msg.msg_type)
            {
                case CommonDefine.MsgType_e.MSG_TCP_CONNECT:
                    {
                        Console.WriteLine("connected");
                        m_mre.Set();
                    }
                    break;
                case CommonDefine.MsgType_e.MSG_TCP_READ:
                    {
                        if (m_state == CmdState.STATE_UPLOADING)
                        {
                            Console.WriteLine("upload finished, response received");
                            string data = msg.msg_data.ToString();
                            Console.WriteLine("response [" + data + "]");
                            m_state = CmdState.STATE_UPLOAD_END;
                            m_mre.Set();
                        }
                        else if (m_state == CmdState.STATE_DOWNLOADING)
                        {
                            try
                            {
                                Console.WriteLine("download finished, now waiting for response...");
                                string data = msg.msg_data.ToString();
                                File.WriteAllText(m_download_file_path, data);
                                m_sock.Receive();
                                m_state = CmdState.STATE_UPLOAD_END;
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message);
                                m_state = CmdState.STATE_DOWNLOAD_END;
                            }
                        }
                        else
                        {
                            Console.WriteLine("response received");
                            string data = msg.msg_data.ToString();
                            Console.WriteLine("response [" + data + "]");
                            m_mre.Set();
                        }
                    }
                    break;
                case CommonDefine.MsgType_e.MSG_TCP_SEND:
                    {
                        if (m_state == CmdState.STATE_UPLOAD_START)
                        {
                            Console.WriteLine("request sent out, now uploading content...");
                            m_state = CmdState.STATE_UPLOADING;
                            try
                            {
                                byte[] content_bytes = File.ReadAllBytes(m_upload_file_path);
                                m_sock.Send(content_bytes);
                            }
                            catch (Exception ex) {
                                Console.WriteLine(ex.Message);
                                m_state = CmdState.STATE_UPLOAD_END;
                            }
                        }
                        else if (m_state == CmdState.STATE_UPLOADING)
                        {
                            Console.WriteLine("uploading content sent out, now waiting response...");
                            m_sock.Receive();
                        }
                        else if (m_state == CmdState.STATE_DOWNLOAD_START)
                        {
                            Console.WriteLine("request send out, now downloading content...");
                            m_state = CmdState.STATE_DOWNLOADING;
                            m_sock.Receive();
                        }
                        else
                        {
                            Console.WriteLine("request send out, now waiting response...");
                            m_sock.Receive();
                        }
                    }
                    break;
                case CommonDefine.MsgType_e.MSG_TCP_ERR:
                    {
                        Console.WriteLine("connection error, close client");
                        m_sock.Close();
                    }
                    break;
                default:
                    {
                        Logger.WriteLog("unknow msg type [" + (int)msg.msg_type + "]");
                    }
                    break;
            }
        }

        private string read_request()
        {
            Console.WriteLine("input request:");
            RequestMsg req_msg = new RequestMsg();
            Console.WriteLine("TYPE:");
            req_msg.type = Console.ReadLine();

            if (req_msg.type == "EXECUTE")
            {
                Console.WriteLine("CMD:");
                req_msg.cmd = Console.ReadLine();
                Console.WriteLine("PARA:");
                req_msg.para = Console.ReadLine();
            }
            else if (req_msg.type == "UPLOAD")
            {
                Console.WriteLine("SRC PATH:");
                req_msg.path_src = Console.ReadLine();
                m_upload_file_path = req_msg.path_src;
                Console.WriteLine("DST PATH:");
                req_msg.path_dst = Console.ReadLine();
                req_msg.content = CalMD5.GetMD5(req_msg.path_src);
                m_state = CmdState.STATE_UPLOAD_START;
            }
            else if (req_msg.type == "DOWNLOAD")
            {
                Console.WriteLine("SRC PATH:");
                req_msg.path_src = Console.ReadLine();
                Console.WriteLine("DST PATH:");
                req_msg.path_dst = Console.ReadLine();
                m_download_file_path = req_msg.path_dst;
                m_state = CmdState.STATE_DOWNLOAD_START;
            }

            string request = m_fomartor.GetRequest(req_msg);
            return request;
        }

        private CmdState m_state;
        private string m_upload_file_path;
        private string m_download_file_path;
        private string m_ip;
        private int m_port;
        AsynTcpSocket m_sock;
        RequestFomator m_fomartor;
        private static ManualResetEvent m_mre = new ManualResetEvent(false);
    }

    public enum CmdState
    {
        STATE_UNKNOWN = -1,

        STATE_UPLOAD_START = 1,
        STATE_UPLOADING,
        STATE_UPLOAD_END,
        STATE_DOWNLOAD_START,
        STATE_DOWNLOADING,
        STATE_DOWNLOAD_END,
    }

    class RequestMsg
    {
        public string type;
        public string para;
        public string path_src;
        public string path_dst;
        public string cmd;
        public string content;
    }

    class RequestFomator
    {
        public string GetRequest(RequestMsg msg)
        {
            string request = "";
            if (msg.type == "EXECUTE") {
                request += "START\n";
                request += "TYPE: " + msg.type + "\n";
                request += "CMD: " + msg.cmd + "\n";
                request += "PARA: " + msg.para + "\n";
                request += "END\n";
            }
            else if (msg.type == "UPLOAD") {
                request += "START\n";
                request += "TYPE: " + msg.type + "\n";
                request += "PATH_SRC: " + msg.path_src + "\n";
                request += "PATH_DST: " + msg.path_dst + "\n";
                request += "CONTENT_LENGTH: " + msg.content.Length + "\n";
                request += "CONTENT_BODY: \n" + msg.content + "\n";
                request += "END\n";
            }
            else if (msg.type == "DOWNLOAD") {
                request += "START\n";
                request += "TYPE: " + msg.type + "\n";
                request += "PATH_SRC: " + msg.path_src + "\n";
                request += "PATH_DST: " + msg.path_dst + "\n";
                request += "END\n";
            }
            return request;
        }
    }
}
